home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
CUJ9208.ARJ
/
1008038A
< prev
next >
Wrap
Text File
|
1992-05-30
|
17KB
|
422 lines
/* RAY_RAD - A Very Simple Ray-Traced Radiosity Renderer */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define FLOOR 0 /* X-Y plane, Z = 0.0 */
#define SOUTH_WALL 1 /* X-Z plane, Y = 0.0 */
#define EAST_WALL 2 /* Y-Z plane, X = 8.0 */
#define NORTH_WALL 3 /* X-Z plane, Y = 8.0 */
#define WEST_WALL 4 /* X-Z plane, X = 0.0 */
#define MAX_RAYS 25000 /* Maximum number of rays */
#define MAX_VAL 1.0e+6 /* Maximum floating point value */
#define MIN_VAL 1.0e-6 /* Minimum floating point value */
#define NUM_LOOP 20 /* Number of iterations */
#define NUM_SURF 10 /* Number of surfaces */
#define PI 3.141592654
#define DRAND() ((double) rand() / (double) RAND_MAX)
typedef struct /* 3-D point co-ordinates */
{
double x; /* X-axis co-ordinate */
double y; /* Y-axis co-ordinate */
double z; /* Z-axis co-ordinate */
} PT_3D;
typedef struct /* 3-D ray */
{
PT_3D org; /* Origin */
PT_3D dir; /* Direction */
} RAY;
typedef struct /* Element */
{
double total; /* Total flux */
double unsent; /* Unsent flux */
} ELEM;
typedef struct /* Surface */
{
PT_3D vertex[4]; /* Vertex array */
int num_row; /* Number of element rows */
int num_col; /* Number of element columns */
double col_dim; /* Element column dimension */
double row_dim; /* Element row dimension */
double emittance; /* Emittance */
double reflectance; /* Reflectance */
ELEM *elemp; /* Element array pointer */
} SURF;
static int send_flux(int, int, int);
static void display_surface(void);
static void find_element(RAY *, int *, int *, int *);
static void global_to_local(int, PT_3D *, PT_3D *);
static void local_to_global(int, RAY *, RAY *);
static void select_ray(int, int, int, RAY *);
static double MaxEmittance = 0.0; /* Maximum emittance */
static SURF RoomSurf[NUM_SURF] = { /* Room surfaces */
{ { { 0.0, 0.0, 0.0 }, { 8.0, 0.0, 0.0 }, /* Floor */
{ 8.0, 8.0, 0.0 }, { 0.0, 8.0, 0.0 } }, 8, 8, 1.0, 1.0,
0.0, 0.2, NULL },
{ { { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 8.0 }, /* South wall */
{ 8.0, 0.0, 8.0 }, { 8.0, 0.0, 0.0 } }, 8, 8, 1.0, 1.0,
0.0, 0.5, NULL },
{ { { 8.0, 0.0, 0.0 }, { 8.0, 0.0, 8.0 }, /* East wall */
{ 8.0, 8.0, 8.0 }, { 8.0, 8.0, 0.0 } }, 8, 8, 1.0, 1.0,
0.0, 0.5, NULL },
{ { { 8.0, 8.0, 0.0 }, { 8.0, 8.0, 8.0 }, /* North wall */
{ 0.0, 8.0, 8.0 }, { 0.0, 8.0, 0.0 } }, 8, 8, 1.0, 1.0,
0.0, 0.5, NULL },
{ { { 0.0, 8.0, 0.0 }, { 0.0, 8.0, 8.0 }, /* West wall */
{ 0.0, 0.0, 8.0 }, { 0.0, 0.0, 0.0 } }, 8, 8, 1.0, 1.0,
0.0, 0.5, NULL },
{ { { 0.0, 0.0, 8.0 }, { 0.0, 3.0, 8.0 }, /* South ceil. */
{ 8.0, 3.0, 8.0 }, { 8.0, 0.0, 8.0 } }, 8, 3, 1.0, 1.0,
0.0, 0.8, NULL },
{ { { 5.0, 3.0, 8.0 }, { 5.0, 5.0, 8.0 }, /* East ceiling */
{ 8.0, 5.0, 8.0 }, { 8.0, 3.0, 8.0 } }, 3, 2, 1.0, 1.0,
0.0, 0.8, NULL },
{ { { 0.0, 5.0, 8.0 }, { 0.0, 8.0, 8.0 }, /* North ceil. */
{ 8.0, 8.0, 8.0 }, { 8.0, 5.0, 8.0 } }, 8, 3, 1.0, 1.0,
0.0, 0.8, NULL },
{ { { 0.0, 3.0, 8.0 }, { 0.0, 5.0, 8.0 }, /* West ceiling */
{ 3.0, 5.0, 8.0 }, { 3.0, 3.0, 8.0 } }, 3, 2, 1.0, 1.0,
0.0, 0.8, NULL },
{ { { 3.0, 3.0, 8.0 }, { 3.0, 5.0, 8.0 }, /* Ceil. light */
{ 5.0, 5.0, 8.0 }, { 5.0, 3.0, 8.0 } }, 2, 2, 1.0, 1.0,
5000.0, 0.8, NULL } };
int main(void)
{
int col; /* Column counter */
int elem; /* Element counter */
int maximum; /* Maximum number of rays */
int num_elem; /* Number of elements */
int num_rays; /* Number of rays */
int row; /* Row counter */
int surf; /* Surface counter */
ELEM *elemp; /* Element pointer */
SURF *surfp; /* Surface pointer */
for (surf = 0; surf < NUM_SURF; surf++) {
/* Instantiate elements */
surfp = &(RoomSurf[surf]);
num_elem = surfp->num_row * surfp->num_col;
if ((surfp->elemp = (ELEM *) malloc(num_elem * sizeof(ELEM)))
== NULL) {
fputs("Out of memory!\n", stderr);
return (2);
}
elemp = surfp->elemp;
for (elem = 0; elem < num_elem; elem++, elemp++)
elemp->total = elemp->unsent = surfp->emittance;
if (surfp->emittance > MaxEmittance)
MaxEmittance = surfp->emittance;
}
do {
/* Distribute flux between elements */
num_rays = 0;
for (surf = 0; surf < NUM_SURF; surf++) {
surfp = &(RoomSurf[surf]);
for (row = 0; row < surfp->num_row; row++)
for (col = 0; col < surfp->num_col; col++) {
if ((maximum = send_flux(surf, row, col)) > num_rays)
num_rays = maximum;
}
}
display_surface(); /* Display intermediate results */
} while (num_rays > 0); /* Repeat until convergence */
for (surf = 0; surf < NUM_SURF; surf++) /* Free memory */
free(RoomSurf[surf].elemp);
return (0);
}
static int send_flux ( /* Send flux to other elements */
int s_surf, /* Sending surface index */
int s_row, /* Sending element row */
int s_col ) /* Sending element column */
{
int h_col; /* Hit element column */
int h_row; /* Hit element row */
int h_surf; /* Hit surface index */
int num_rays; /* Number of rays */
int ray; /* Ray counter */
double inc_flux; /* Incident (ray) flux */
double ref_flux; /* Reflected flux */
RAY shoot; /* Shooting ray */
ELEM *h_elemp; /* Hit element pointer */
ELEM *s_elemp; /* Sending element pointer */
SURF *h_surfp; /* Hit surface pointer */
SURF *s_surfp; /* Sending surface pointer */
s_surfp = &(RoomSurf[s_surf]);
s_elemp = s_surfp->elemp + s_row * s_surfp->num_col + s_col;
/* Number of rays to shoot proportional to unsent flux */
if ((num_rays = (int) (MAX_RAYS * s_elemp->unsent /
MaxEmittance)) == 0)
return (0);
inc_flux = s_elemp->unsent / num_rays; /* Get ray flux */
for (ray = 0; ray < num_rays; ray++) { /* Distribute flux */
select_ray(s_surf, s_row, s_col, &shoot); /* Select ray */
/* Find hit surface and element */
find_element(&shoot, &h_surf, &h_row, &h_col);
/* Calculate flux reflected from hit element */
h_surfp = &(RoomSurf[h_surf]);
h_elemp = h_surfp->elemp + h_row * h_surfp->num_col + h_col;
ref_flux = h_surfp->reflectance * inc_flux;
h_elemp->total += ref_flux; /* Update total flux */
h_elemp->unsent += ref_flux; /* Update unsent flux */
}
s_elemp->unsent = 0.0; /* Reset sender's unsent flux */
return (num_rays);
}
static void select_ray ( /* Randomly select ray */
int surf, /* Surface index */
int row, /* Element row */
int col, /* Element column */
RAY *rayp ) /* Ray pointer */
{
double horz; /* Ray direction local horizontal angle */
double vert; /* Ray direction local vertical angle */
RAY local; /* Ray local co-ordinates */
SURF *surfp; /* Surface pointer */
surfp = &(RoomSurf[surf]);
/* Randomly select local (surface) ray origin co-ordinates */
/* within sending element boundary */
local.org.x = ((double) col + DRAND()) / surfp->col_dim;
local.org.y = ((double) row + DRAND()) / surfp->row_dim;
local.org.z = 0.0;
/* Randomly select local (surface) ray direction co-ordinates */
/* with cosine probability distribution in vertical plane */
horz = 2.0 * PI * DRAND(); /* Horizontal angle */
vert = acos(sqrt(1.0 - DRAND())); /* Vertical angle */
/* Convert from spherical to rectilinear co-ordinates */
local.dir.x = sin(vert) * cos(horz);
local.dir.y = sin(vert) * sin(horz);
local.dir.z = cos(vert);
/* Convert ray co-ordinates from local to global */
local_to_global(surf, &local, rayp);
}
static void find_element ( /* Find intersected element */
RAY *rayp, /* Ray pointer */
int *h_surfp, /* Hit surface index pointer */
int *h_rowp, /* Hit element row pointer */
int *h_colp ) /* Hit element column pointer */
{
int surf; /* Surface counter */
double s = MAX_VAL; /* Smallest parametric value */
double t; /* Current parametric value */
PT_3D hit; /* Hit point co-ordinates */
PT_3D temp; /* Temporary point co-ordinates */
SURF *surfp; /* Surface pointer */
for (surf = 0; surf < NUM_SURF; surf++) {
surfp = &(RoomSurf[surf]);
/* Determine if and where ray intersects surface plane */
switch (surf) {
case EAST_WALL:
case WEST_WALL:
if (fabs(rayp->dir.x) > MIN_VAL) {
t = (surfp->vertex[0].x - rayp->org.x) / rayp->dir.x;
if (t > MIN_VAL && t < s) {
s = t;
*h_surfp = surf;
}
}
break;
case SOUTH_WALL:
case NORTH_WALL:
if (fabs(rayp->dir.y) > MIN_VAL) {
t = (surfp->vertex[0].y - rayp->org.y) / rayp->dir.y;
if (t > MIN_VAL && t < s) {
s = t;
*h_surfp = surf;
}
}
break;
case FLOOR:
if (fabs(rayp->dir.z) > MIN_VAL) {
t = (surfp->vertex[0].z - rayp->org.z) / rayp->dir.z;
if (t > MIN_VAL && t < s) {
s = t;
*h_surfp = surf;
}
}
break;
default:
if (fabs(rayp->dir.z) > MIN_VAL) {
t = (surfp->vertex[0].z - rayp->org.z) / rayp->dir.z;
if (t > MIN_VAL && t < s) {
/* Check for intersection inside surface boundary */
temp.x = rayp->org.x + t * rayp->dir.x;
temp.y = rayp->org.y + t * rayp->dir.y;
if ((temp.x >= surfp->vertex[0].x && temp.x <
surfp->vertex[3].x) && (temp.y >=
surfp->vertex[0].y && temp.y <
surfp->vertex[1].y)) {
s = t;
*h_surfp = surf;
}
}
}
break;
}
}
/* Calculate hit point global co-ordinates */
temp.x = rayp->org.x + s * rayp->dir.x;
temp.y = rayp->org.y + s * rayp->dir.y;
temp.z = rayp->org.z + s * rayp->dir.z;
/* Convert global to local (surface) co-ordinates */
global_to_local(*h_surfp, &temp, &hit);
/* Calculate hit element row and column indices */
*h_rowp = (int) (hit.y / surfp->row_dim);
*h_colp = (int) (hit.x / surfp->col_dim);
}
static void global_to_local ( /* Convert global to local */
int surf, /* Surface index */
PT_3D *globalp, /* Global co-ordinates pointer */
PT_3D *localp ) /* Local co-ordinates pointer */
{
PT_3D *vp; /* Vertex pointer */
vp = &(RoomSurf[surf].vertex[0]);
switch (surf) {
case FLOOR:
localp->x = globalp->x - vp->x;
localp->y = globalp->y - vp->y;
break;
case SOUTH_WALL:
localp->x = globalp->z - vp->z;
localp->y = globalp->x - vp->x;
break;
case EAST_WALL:
localp->x = globalp->z - vp->z;
localp->y = globalp->y - vp->y;
break;
case NORTH_WALL:
localp->x = globalp->z - vp->z;
localp->y = vp->x - globalp->x;
break;
case WEST_WALL:
localp->x = globalp->z - vp->z;
localp->y = vp->y - globalp->y;
break;
default:
localp->x = globalp->y - vp->y;
localp->y = globalp->x - vp->x;
break;
}
}
static void local_to_global ( /* Convert ray co-ordinates */
int surf, /* Surface index */
RAY *localp, /* Local co-ordinates pointer */
RAY *globalp ) /* Global co-ordinates pointer */
{
PT_3D *vp; /* Vertex pointer */
vp = &(RoomSurf[surf].vertex[0]);
switch (surf) {
case FLOOR:
globalp->org.x = vp->x + localp->org.x;
globalp->org.y = vp->y + localp->org.y;
globalp->org.z = vp->z + localp->org.z;
globalp->dir.x = localp->dir.x;
globalp->dir.y = localp->dir.y;
globalp->dir.z = localp->dir.z;
break;
case SOUTH_WALL:
globalp->org.x = vp->x + localp->org.y;
globalp->org.y = vp->y + localp->org.z;
globalp->org.z = vp->z + localp->org.x;
globalp->dir.x = localp->dir.y;
globalp->dir.y = localp->dir.z;
globalp->dir.z = localp->dir.x;
break;
case EAST_WALL:
globalp->org.x = vp->x - localp->org.z;
globalp->org.y = vp->y + localp->org.y;
globalp->org.z = vp->z + localp->org.x;
globalp->dir.x = -localp->dir.z;
globalp->dir.y = localp->dir.y;
globalp->dir.z = localp->dir.x;
break;
case NORTH_WALL:
globalp->org.x = vp->x - localp->org.y;
globalp->org.y = vp->y - localp->org.z;
globalp->org.z = vp->z + localp->org.x;
globalp->dir.x = -localp->dir.y;
globalp->dir.y = -localp->dir.z;
globalp->dir.z = localp->dir.x;
break;
case WEST_WALL:
globalp->org.x = vp->x + localp->org.z;
globalp->org.y = vp->y - localp->org.y;
globalp->org.z = vp->z + localp->org.x;
globalp->dir.x = localp->dir.z;
globalp->dir.y = -localp->dir.y;
globalp->dir.z = localp->dir.x;
break;
default:
globalp->org.x = vp->x + localp->org.y;
globalp->org.y = vp->y + localp->org.x;
globalp->org.z = vp->z - localp->org.z;
globalp->dir.x = localp->dir.y;
globalp->dir.y = localp->dir.x;
globalp->dir.z = -localp->dir.z;
break;
}
}
static void display_surface(void) /* Display surfaces */
{
int col; /* Element column index */
int row; /* Element row index */
int surf; /* Surface counter */
ELEM *elemp; /* Element pointer */
SURF *surfp; /* Surface pointer */
static int loop = 0; /* Iteration counter */
printf("Loop %d\n", loop++);
for (surf = 0; surf < NUM_SURF; surf++) {
printf("Surface %d\n", surf);
surfp = &(RoomSurf[surf]);
for (row = 0; row < surfp->num_row; row++) {
for (col = 0; col < surfp->num_col; col++) {
elemp = surfp->elemp + row * surfp->num_col + col;
printf("% 8.2f ", elemp->total / (PI * surfp->row_dim *
surfp->col_dim));
}
putchar('\n');
}
}
}